#pragma once // 防止头文件重复包含
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>
using namespace std;

template<class T>
class BlockQueue
{
    static const int defaultnum = 20; //默认容量为20
private:
    inline void Lock()
    {
        pthread_mutex_lock(&_mutex); //拿锁
    }
    inline void Unlock()
    {
        pthread_mutex_unlock(&_mutex); //解锁
    }
    inline void Wait(pthread_cond_t* cond)
    {
        pthread_cond_wait(cond, &_mutex);
    }
    inline void Wake(pthread_cond_t* cond)
    {
        pthread_cond_signal(cond);
        //pthread_cond_broadcast(cond); //可能造成伪唤醒状态
    }
public:
    BlockQueue(int num = defaultnum)
        :_maxcap(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }
    void Pop(T *out) //消费者的消费行为->尽量不要返回一个局部对象
    {
        //在进行拿去之前需要拿锁
        Lock();
        while(_q.empty()) //死循环一致判断当前的状态是否满足—>避免伪唤醒状态
            Wait(&_c_cond); //让消费者在条件变量下等待 
        
        *out = _q.front(); //用数据带出去
        _q.pop();

        Wake(&_p_cond); //现在消费了数据，通知生产者生产
        Unlock(); //解锁

    }
    void Push(const T& in) //生产者的行为
    {
        Lock();
        while(_q.size() == _maxcap) //同样防止伪唤醒
            Wait(&_p_cond);
        
        _q.push(in); //生产数据

        Wake(&_c_cond); //唤醒消费者
        Unlock(); //解锁
    }

private:
    int _maxcap; //最大容量
    queue<T> _q; //阻塞队列,共享的资源
    pthread_mutex_t _mutex; //互斥量—>在阻塞队列中
    // 消费者和生产者共用一把锁
    pthread_cond_t _c_cond; //消费者的信号量
    pthread_cond_t _p_cond; //生产者的信号量

};